'use strict';

const Service = require('egg').Service;

class BaseService extends Service {
  /**
   * @description 捕获错误
   * @param callback 回调函数
   * */
  run(callback) {
    const { ctx, app } = this;
    try {
      if (callback) { return callback(ctx, app); }
    } catch (e) {
      console.log(e);
      return null;
    }
  }

  /**
   * @description 获取模型实例
   * */
  _getModel() {
    const { app } = this;
    return app.model[this._model];
  }

  /**
   * @description 创建模型的模板
   * @param body 新增内容实例
   * */
  async _create(body) {
    return this.run(async () => {
      const result = await this._getModel().create(body);
      return result.dataValues;
    });
  }

  /**
   * @description 查找单个数据模板
   * @param whereOp 查询条件
   * @param include 关联查询参数
   * */
  async _findOne({ where, include, attributes = { exclude: [ 'deletedAt' ] }, paranoid = true }) {
    return this.run(async () => {
      const result = await this._getModel().findOne({
        where,
        include,
        attributes,
        paranoid,
      });
      return result ? result.dataValues : null;
    });
  }

  /**
   * @description 更新数据模板
   * @param whereOp 查询条件
   * @param body 修改内容
   * */
  async _update({ body, where }) {
    return this.run(async () => {
      const result = await this._getModel().update(body, { where });
      return result ? result : null;
    });
  }

  /**
   * @description 删除数据模板
   * @param where 删除条件
   * */
  async _destory({ where }) {
    return this.run(async () => {
      const result = await this._getModel().destroy({ where });
      return result ? result > 0 : null;
    });
  }

  /**
   * @description 恢复数据模板
   * @param where 删除条件
   * */
  async _restore({ where }) {
    return this.run(async () => {
      const result = await this._getModel().restore({ where });
      return result ? result > 0 : null;
    });
  }

  /**
   * @description 判断是否存在模板
   * @param where 删除条件
   * */
  async _isExist({ where, paranoid = true }) {
    return this.run(async () => {
      const result = await this._getModel().findOne({
        where,
        paranoid,
      });
      return result ? true : null;
    });
  }

  /**
   * @description 条件查询模板
   * @param order 排序条件
   * @param where 搜索条件
   * @param pageSize 页面尺寸
   * @param pageIndex 页面页码
   * @param others 其他参数
   * @param attributes 显示的数据 默认不显示更新时间和删除时间
   * */
  async _findList({ order = [[ 'createdAt', 'desc' ]], where = {}, pageSize = 10, pageIndex = 0, include = [], attributes = { exclude: [ 'deletedAt', 'updatedAt' ] }, paranoid = true }) {
    return this.run(async () => {
      const result = await this._getModel().findAndCountAll({
        limit: +pageSize,
        offset: pageSize * pageIndex,
        order,
        where,
        include,
        attributes,
        paranoid,
      });
      return result ? {
        count: result.count,
        data: result.rows,
      } : null;
    });
  }

  /**
   * @description 查询所有数据模板
   * @param where 查询条件
   * */
  async _findAll({ where, include = [], attributes = { exclude: [ 'deletedAt', 'updatedAt' ] }, paranoid = true } = {}) {
    return this.run(async () => {
      const result = await this._getModel().findAll({ where, attributes, paranoid, include });
      return result ? result.map(item => item.dataValues) : null;
    });
  }

  /**
   * @description 格式化where条件
   * @param exact 精确查询
   * @param dim 模糊查询
   * @param range 范围查询
   * @param eq ==查询
   * @param ne !=查询
   * @param isNull 判断是否为空
   * @param gt 大于操作符
   * @param lt 小于操作符
   * @param gte 小于操作符
   * @param lte 小于操作符
   * */
  formatWhere({ exact, dim, range, inOp, ne, isNull, gt, lt, gte, lte }) {
    const where = {};
    const { app } = this;
    const { Op } = app.Sequelize;

    // 精确查询
    if (exact) {
      for (const key of Object.keys(exact)) {
        if (exact[key] !== undefined) {
          where[key] = exact[key];
        }
      }
    }

    // 模糊查询
    if (dim) {
      for (const key of Object.keys(dim)) {
        if (dim[key] !== undefined) {
          where[key] = {
            [Op.like]: `%${dim[key]}%`,
          };
        }
      }
    }

    // 范围查询
    if (range) {
      for (const key of Object.keys(range)) {
        if (range[key] !== undefined) {
          if (range[key] instanceof Array && range[key].length === 2) {
            where[key] = {
              [Op.between]: [ range[key][0], range[key][1] ],
            };
          }
        }
      }
    }

    // in 查询
    if (inOp) {
      for (const key of Object.keys(inOp)) {
        if (inOp[key] !== undefined) {
          if (inOp[key] instanceof Array) {
            where[key] = {
              [Op.in]: inOp[key],
            };
          } else if (typeof inOp[key] === 'string') {
            where[key] = {
              [Op.in]: inOp[key].split(','),
            };
          }
        }
      }
    }

    // !=查询
    if (ne) {
      for (const key of Object.keys(ne)) {
        if (ne[key] !== undefined) {
          where[key] = {
            [Op.ne]: ne[key],
          };
        }
      }
    }

    if (isNull) {
      for (const key of Object.keys(isNull)) {
        if (isNull[key] !== undefined) {
          where[key] = {
            [Op.is]: null,
          };
        }
      }
    }

    if (gt) {
      for (const key of Object.keys(gt)) {
        if (gt[key] !== undefined) {
          where[key] = {
            [Op.gt]: gt[key],
          };
        }
      }
    }

    if (lt) {
      for (const key of Object.keys(lt)) {
        if (lt[key] !== undefined) {
          where[key] = {
            [Op.lt]: lt[key],
          };
        }
      }
    }

    if (gte) {
      for (const key of Object.keys(gte)) {
        if (gte[key] !== undefined) {
          where[key] = {
            [Op.gte]: gte[key],
          };
        }
      }
    }

    if (lte) {
      for (const key of Object.keys(lte)) {
        if (lte[key] !== undefined) {
          where[key] = {
            [Op.lte]: lte[key],
          };
        }
      }
    }

    return where;
  }

  formatOrder(prop, sort) {
    if (!prop || !sort) {
      return [[ 'createdAt', 'desc' ]];
    }
    if (sort === '0') {
      return [[ prop, 'desc' ]];
    }
    return [[ prop, 'asc' ]];
  }

  rangeWhere({ startTime, endTime, houseId, status } = {}) {
    if (!startTime || !endTime) {
      return {};
    }
    const { app } = this;
    const { Op } = app.Sequelize;
    const where = {
      [Op.and]: [
        { houseId },
        { status:
            {
              [Op.in]: status,
            },
        },
        {
          [Op.or]: [
            {
              [Op.and]: [
                {
                  startTime: {
                    [Op.between]: [ startTime, endTime ],
                  },
                },
              ],
            },
            {
              [Op.and]: [
                {
                  endTime: {
                    [Op.between]: [ startTime, endTime ],
                  },
                },
              ],
            },
          ],
        },
      ],
    };

    return where;
  }

  // 执行sql语句(查询类型)
  async querySelect(sql, replacements = {}) {
    return this.run(async () => {
      const { app } = this;
      const { QueryTypes } = app.Sequelize;
      const result = await app.model.query(sql, { type: QueryTypes.SELECT, replacements });
      return result;
    });
  }
}

module.exports = BaseService;
